/*
 * LunTimeStatistics.cpp
 *
 *  Created on: Dec 16, 2011
 *      Author: Netali
 */

#include "LunTimeStatistics.h"
#include <iostream>


using namespace std;

string convertInt1(int number){
    if (number == 0)
        return "0";
    string temp="";
    string returnvalue="";
    while (number>0)
    {
        temp+=number%10+48;
        number/=10;
    }
    for (int i=0;i<(int)temp.length();i++)
        returnvalue+=temp[temp.length()-i-1];
    return returnvalue;
}


LunTimeStatistics::LunTimeStatistics (int id , int time) {
	my_time = time;
	for(int i=0; i<numStats; i++)
		statistics[i] = 0;
	lun_id = id;
	responseTime=0;
}

int LunTimeStatistics::getTime(){
	return my_time;
}

double LunTimeStatistics::getStatistic(int place){
	return statistics[place-1];
}

void LunTimeStatistics::addStatistics(float newStat[numStats]){
	for (int i=0; i<numStats; i++)
		statistics[i] = statistics[i] + newStat[i];
}

string LunTimeStatistics::toString(){
	string str = "";

	str.append(convertInt1(my_time));
	for (int i=0; i<numStats; i++){
		str.append(" ");
		str.append(convertInt1(statistics[i]));
	}
	return str;
}

void LunTimeStatistics::calcResponseTime(double ssdRead, double ssdKb, double fcRead, double fcKb, double sataRead, double sataKb, DeviceData* ssd, DeviceData* fc, DeviceData* sata, int priorityGroup){
	
	// make sure the number of misses received is the same as previously calculated
	// if there is no cache partition the number of misses wont be counted

	/*
	highest priority: uw/(1-u1)+w
	medium priority: uw/((1-u2-u1)*(1-u1))+w
	low priority: uw/((1-u1-u2-u3)*(1-u2-u1))+w
	*/

	double ssdNum=0, fcNum=0, sataNum=0;
	
	ssdNum=((ssdKb/1024.0)/ssd->getReadRate())+(ssd->getOverhead()*ssdRead);

	fcNum=((fcKb/1024.0)/fc->getReadRate())+(fc->getOverhead()*fcRead);

	sataNum=((sataKb/1024.0)/sata->getReadRate())+(sata->getOverhead()*sataRead);
	
	if (priorityGroup==1){
		ssdNum=(((ssd->getUtilizationRecord(my_time)*ssdNum)/(1-ssd->getUtilizationRecordU1(my_time)))+ssdNum);
		fcNum=(((fc->getUtilizationRecord(my_time)*fcNum)/(1-fc->getUtilizationRecordU1(my_time)))+fcNum);
		sataNum=(((sata->getUtilizationRecord(my_time)*sataNum)/(1-sata->getUtilizationRecordU1(my_time)))+sataNum);
	}
	else if (priorityGroup==2){
		ssdNum=(((ssd->getUtilizationRecord(my_time)*ssdNum)/((1-ssd->getUtilizationRecordU2(my_time)-ssd->getUtilizationRecordU1(my_time))*(1-ssd->getUtilizationRecordU1(my_time))))+ssdNum);
		fcNum=(((fc->getUtilizationRecord(my_time)*fcNum)/((1-fc->getUtilizationRecordU2(my_time)-fc->getUtilizationRecordU1(my_time))*(1-fc->getUtilizationRecordU1(my_time))))+fcNum);
		sataNum=(((sata->getUtilizationRecord(my_time)*sataNum)/((1-sata->getUtilizationRecordU2(my_time)-sata->getUtilizationRecordU1(my_time))*(1-sata->getUtilizationRecordU1(my_time))))+sataNum);
	}
	else{
		ssdNum=(((ssd->getUtilizationRecord(my_time)*ssdNum)/((1-ssd->getUtilizationRecordU1(my_time)-ssd->getUtilizationRecordU2(my_time)-ssd->getUtilizationRecordU3(my_time))*(1-ssd->getUtilizationRecordU1(my_time)-ssd->getUtilizationRecordU2(my_time))))+ssdNum);
		fcNum=(((fc->getUtilizationRecord(my_time)*fcNum)/((1-fc->getUtilizationRecordU1(my_time)-fc->getUtilizationRecordU2(my_time)-fc->getUtilizationRecordU3(my_time))*(1-fc->getUtilizationRecordU1(my_time)-fc->getUtilizationRecordU2(my_time))))+fcNum);
		sataNum=(((sata->getUtilizationRecord(my_time)*sataNum)/((1-sata->getUtilizationRecordU1(my_time)-sata->getUtilizationRecordU2(my_time)-sata->getUtilizationRecordU3(my_time))*(1-sata->getUtilizationRecordU1(my_time)-sata->getUtilizationRecordU2(my_time))))+sataNum);
	}


	// normalizing response time
	responseTime=ssdNum+fcNum+sataNum;

	if ((ssdRead+fcRead+sataRead)==0)
		responseTime=0;
	else
		responseTime=responseTime/(ssdRead+fcRead+sataRead);

	if (responseTime < 0){
		cout << "response time < 0" << endl;
	}
}

void LunTimeStatistics::calcResponseTimeGD(double ssdRead, double ssdKb, double fcRead, double fcKb, double sataRead, double sataKb, DeviceData* ssd, DeviceData* fc, DeviceData* sata, double ssdU[], double fcU[], double sataU[], int priorityGroup){
	
	// make sure the number of misses received is the same as previously calculated
	// if there is no cache partition the number of misses wont be counted

	/*
	highest priority: uw/(1-u1)+w
	medium priority: uw/((1-u2-u1)*(1-u1))+w
	low priority: uw/((1-u1-u2-u3)*(1-u2-u1))+w
	*/

	double ssdNum=0, fcNum=0, sataNum=0;
	
	ssdNum=((ssdKb/1024.0)/ssd->getReadRate())+(ssd->getOverhead()*ssdRead);

	fcNum=((fcKb/1024.0)/fc->getReadRate())+(fc->getOverhead()*fcRead);

	sataNum=((sataKb/1024.0)/sata->getReadRate())+(sata->getOverhead()*sataRead);
	
	if (priorityGroup==1){
		ssdNum=(((ssdU[0]*ssdNum)/(1-ssdU[1]))+ssdNum);
		fcNum=(((fcU[0]*fcNum)/(1-fcU[1]))+fcNum);
		sataNum=(((sataU[0]*sataNum)/(1-sataU[1]))+sataNum);
	}
	else if (priorityGroup==2){
		ssdNum=(((ssdU[0]*ssdNum)/((1-ssdU[2]-ssdU[1])*(1-ssdU[1])))+ssdNum);
		fcNum=(((fcU[0]*fcNum)/((1-fcU[2]-fcU[1])*(1-fcU[1])))+fcNum);
		sataNum=(((sataU[0]*sataNum)/((1-sataU[2]-sataU[1])*(1-sataU[1])))+sataNum);
	}
	else{
		ssdNum=(((ssdU[0]*ssdNum)/((1-ssdU[1]-ssdU[2]-ssdU[3])*(1-ssdU[1]-ssdU[2])))+ssdNum);
		fcNum=(((fcU[0]*fcNum)/((1-fcU[1]-fcU[2]-fcU[3])*(1-fcU[1]-fcU[2])))+fcNum);
		sataNum=(((sataU[0]*sataNum)/((1-sataU[1]-sataU[2]-sataU[3])*(1-sataU[1]-sataU[2])))+sataNum);
	}


	// normalizing response time
	responseTime=ssdNum+fcNum+sataNum;

	if ((ssdRead+fcRead+sataRead)==0)
		responseTime=0;
	else
		responseTime=responseTime/(ssdRead+fcRead+sataRead);
	

	if (responseTime < 0){
		cout << "response time < 0" << endl;
	}
}


void LunTimeStatistics::startOver(){
	for(int i=0; i<numStats; i++)
		statistics[i] = 0;
}
